﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LaughingDog.GameObjects;
using Microsoft.Xna.Framework.Audio;
using LaughingDog.Managers;
using Microsoft.Xna.Framework;

namespace LaughingDog.Components
{
    public class AudioSource : Behaviour
    {        
        private SoundEffect mSoundEffect = null;
        private SoundEffectInstance mSoundEffectInstance = null;
        private String mAssetName = "";        
        private Single mMaxVolume = 5.0f;
        private Single mMinVolume = 0.5f;        
        private Single mDistanceFromListener = 0;
        private Vector2 mDirectionToListener = Vector2.Zero;        
        private AudioEmitter mEmitter;
        private Boolean mPlaying2D = false;

        /// <summary>
        /// 
        /// </summary>
        public String AssetName { get { return mAssetName; } set { mAssetName = value; loadSound(mAssetName); } }

        /// <summary>
        /// 
        /// </summary>
        public Single Volume { get { return mSoundEffectInstance.Volume; } set { mSoundEffectInstance.Volume = value; } }

        /// <summary>
        /// 
        /// </summary>
        public Single Pitch { get { return mSoundEffectInstance.Pitch; } set { mSoundEffectInstance.Pitch = value; } }

        /// <summary>
        /// 
        /// </summary>
        public Single Pan { get { return mSoundEffectInstance.Pan; } set { mSoundEffectInstance.Pan = value; } }

        /// <summary>
        /// Gets or sets a value indicating whether this AudioSource should loop or not.
        /// </summary>
        public Boolean IsLooped { get { return mSoundEffectInstance.IsLooped; } set { mSoundEffectInstance.IsLooped = value; } }
        
        /// <summary>
        /// The maximum volume this AudioSource will play at.
        /// </summary>
        public Single MaxVolume { get { return mMaxVolume; } set { mMaxVolume = value; } }

        /// <summary>
        /// The minimum volume this AudioSource will play at.
        /// </summary>
        public Single MinVolume { get { return mMinVolume; } set { mMinVolume = value; } }
        //public Single RollOffFactor { get { return mRollOffFactor; } set { mRollOffFactor = value; } }

        /// <summary>
        /// Gets the current State of this AudioSource.
        /// </summary>
        public SoundState State { get { return mSoundEffectInstance.State; } }

        /// <summary>
        /// Creates a new instance of an AudioSource.
        /// </summary>
        /// <param name="gameObject">The GameObject this Component should be attached to.</param>
        public AudioSource(GameObject gameObject)
            : base(gameObject)
        {
            mEmitter = new AudioEmitter();
            mEmitter.DopplerScale = 10000;
        }

        private void loadSound(String assetName)
        {
            mSoundEffect = AssetManager.Instance.Load<SoundEffect>(assetName);

            mSoundEffectInstance = mSoundEffect.CreateInstance();   
        }

        private void adjustVolume()
        {
            if (Volume > MaxVolume)
                Volume = MaxVolume;
            else if (Volume < MinVolume)
                Volume = MinVolume;
        } 

        /// <summary>
        /// Updates this AudioSource.
        /// </summary>
        public override void Update()
        {
            mEmitter.Position = new Vector3(Transform.Position, 0);

            if (AudioReceiver.ActiveReceiver != null)
            {
                mDistanceFromListener = Vector2.Distance(Transform.Position, AudioReceiver.ActiveReceiver.Transform.Position);                               
            }

            if (mPlaying2D && State == SoundState.Playing)
            {
                //mSoundEffectInstance.Volume = mDistanceFromListener * 0.1f;
            }

            base.Update();
        }

        /// <summary>
        /// Plays the AudioSource with current settings not taking into account 2D position.
        /// </summary>
        public void Play()
        {
            adjustVolume();

            if (mSoundEffectInstance != null)
                mSoundEffectInstance.Play(); mPlaying2D = false;   
        }

        /// <summary>
        /// Plays the AudioSource with specific settings not taking into account 2D position.
        /// </summary>
        /// <param name="volume">The volume the AudioSource should play at.</param>
        /// <param name="pitch">The pitch the AudioSource should play in.</param>
        /// <param name="pan">The amount of panning applied to the AudioSource.</param>
        public void Play(Single volume, Single pitch, Single pan)
        {
            Volume = volume;
            Pitch = pitch;
            Pan = pan;

            adjustVolume();

            if (mSoundEffectInstance != null)
                mSoundEffectInstance.Play(); mPlaying2D = false;
        }

        /// <summary>
        /// Plays the AudioSource with automatic settings based on its position from the global AudioListener.
        /// </summary>
        public void Play2D()
        {
            throw new NotImplementedException();

            //adjustVolume();

            //if (State == SoundState.Paused)
            //{
            //    if (mSoundEffectInstance != null)
            //        mSoundEffectInstance.Resume(); mPlaying2D = true;
            //}
            //else
            //{
            //    if (mSoundEffectInstance != null)
            //    {
            //        mSoundEffectInstance.Pitch = 1;
            //        mSoundEffectInstance.Apply3D(AudioReceiver.ActiveReceiver.Listener, mEmitter);
            //        mSoundEffectInstance.Play(); mPlaying2D = true;
            //    }
            //}
   
        }

        /// <summary>
        /// Stops the playback of the AudioSource.
        /// </summary>
        public void Stop()
        {
            if (mSoundEffectInstance != null)
                mSoundEffectInstance.Stop(); mPlaying2D = false;
        }

        /// <summary>
        /// Stops the playback of the AudioSource immediately.
        /// </summary>
        /// <param name="immediate">Value indicating whether the AudioSource should be stopped straight away or as authored.</param>
        public void Stop(Boolean immediate)
        {
            if (mSoundEffectInstance != null)
                mSoundEffectInstance.Stop(immediate); mPlaying2D = false;          
        }

        /// <summary>
        /// Pauses the playback of this AudioSource.
        /// </summary>
        public void Pause()
        {
            if (mSoundEffectInstance != null)
                mSoundEffectInstance.Pause(); mPlaying2D = false;
        }        
    }
}
